#include <bits/stdc++.h>
using namespace std;

// 算法思路：
// 1. 将限制条件转化为有向图：从A[i]向i连一条边
// 2. 如果图中有环，环上的点对应的x值应该相等
// 3. 进一步地，强连通分量内的所有点对应的x值应该相等
// 4. 因此第一步是进行强连通分量缩点，将图转化为DAG
// 5. 由于每个点入度严格=1，缩点后的图是一个森林
// 6. 使用树形DP求解方案数

const int MOD = 998244353;    // 模数
const int MAXN = 200000 + 10; // 最大节点数
using ll = long long;         // 长整型别名

int n, m;   // n: 节点数, m: 数字范围上限
ll a[MAXN]; // 输入数组，表示每个节点的前驱

vector<int> G[MAXN]; // 原始图的邻接表

vector<int> scc[MAXN]; // 存储每个强连通分量包含的节点
int num_scc;           // 强连通分量的数量
int scc_id[MAXN];      // 每个节点所属的强连通分量编号

// Tarjan算法相关变量
int low[MAXN], dfn[MAXN],
    timestamp; // low: 最小时间戳, dfn: 发现时间戳, timestamp: 时间戳计数器
bool on_stack[MAXN]; // 标记节点是否在栈中
stack<int> st;       // DFS栈

// Tarjan算法实现 - 寻找强连通分量
void tarjan(int u) {
  // 初始化当前节点的发现时间和最小时间戳
  dfn[u] = low[u] = ++timestamp;
  st.push(u);         // 将当前节点入栈
  on_stack[u] = true; // 标记节点在栈中

  // 遍历当前节点的所有邻居
  for (int v : G[u]) {
    if (!dfn[v]) {                  // 如果邻居节点未被访问过
      tarjan(v);                    // 递归访问邻居节点
      low[u] = min(low[u], low[v]); // 更新当前节点的最小时间戳
    } else if (on_stack[v]) {       // 如果邻居节点在栈中（形成回路）
      low[u] = min(low[u], dfn[v]); // 更新当前节点的最小时间戳
    }
  }

  // 关键判断：如果当前节点是强连通分量的根节点
  if (low[u] == dfn[u]) {
    ++num_scc; // 增加强连通分量计数
    while (true) {
      int v = st.top();          // 取出栈顶节点
      st.pop();                  // 弹出栈顶
      on_stack[v] = false;       // 标记节点不在栈中
      scc[num_scc].push_back(v); // 将节点加入当前强连通分量
      scc_id[v] = num_scc;       // 记录节点所属的强连通分量编号
      if (v == u)                // 如果当前节点是强连通分量的根节点
        break;                   // 结束循环
    }
  }
}

// 对整个图执行Tarjan算法
void tarjan() {
  for (int u = 1; u <= n; ++u) {
    if (!dfn[u]) // 如果节点未被访问过
      tarjan(u); // 执行Tarjan算法
  }
}

// 强连通分量缩点后的图
vector<int> scc_e[MAXN]; // 缩点后的图的邻接表
int in_deg[MAXN];        // 每个强连通分量的入度

// 构建缩点后的图
void build_scc_e() {

  for (int i = 1; i <= num_scc; ++i) {
    /* for (int v : scc[i]) {
       printf("\n");
     }
     */

    // 遍历原始图中的所有边
    for (int u = 1; u <= n; ++u) {
      for (int v : G[u]) {
        if (scc_id[u] != scc_id[v]) { // 如果边的两个端点属于不同的强连通分量
          scc_e[scc_id[u]].push_back(scc_id[v]); // 在缩点后的图中添加边
          in_deg[scc_id[v]] += 1;                // 增加目标强连通分量的入度
        }
      }
    }
    // 去重处理，确保每个强连通分量的邻居唯一
    for (int i = 1; i <= num_scc; ++i) {
      sort(scc_e[i].begin(), scc_e[i].end());
      scc_e[i].resize(unique(scc_e[i].begin(), scc_e[i].end()) -
                      scc_e[i].begin());
    }
  }
}

ll dp[MAXN][MAXN];
// DP数组：dp[i][j]表示以i为根的子树，i所在强连通分量对应的x值<=j的方案数

// 树形DP计算方案数
void calc_dp(int u) {
  // 先递归计算所有子节点的DP值
  for (int v : scc_e[u])
    calc_dp(v);

  // 对每个可能的x值进行DP计算
  for (int j = 1; j <= m; ++j) {
    ll prod = 1; // 子节点方案数的乘积
    for (int v : scc_e[u]) {
      prod = prod * dp[v][j]; // 乘以子节点的方案数
      prod %= MOD;            // 取模
    }
    // 状态转移方程：dp[u][j] = dp[u][j-1] + ∏(子节点v的dp[v][j])
    dp[u][j] = (dp[u][j - 1] + prod) % MOD;
  }
}

// 主求解函数
ll solve() {
  ll ans = 1; // 初始化答案为1
  // 遍历所有强连通分量，从入度为0的根节点开始计算
  for (int u = 1; u <= num_scc; ++u) {
    if (in_deg[u] == 0) {         // 如果是根节点（入度为0）
      calc_dp(u);                 // 计算该子树的DP值
      ans = ans * dp[u][m] % MOD; // 乘以该子树的方案数
    }
  }
  return ans; // 返回总方案数
}

int main() {
  // 读取输入
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    cin >> a[i];
    if (a[i] == i) // 如果自环，跳过
      continue;
    G[a[i]].push_back(i); // 添加边：从a[i]指向i
  }

  tarjan(); // 执行Tarjan算法进行强连通分量分解

  build_scc_e(); // 构建缩点后的图

  // 注意：这里应该调用solve()函数而不是输出函数指针
  cout << solve() << endl; // 输出结果

  return 0;
}